home *** CD-ROM | disk | FTP | other *** search
/ Graphics Plus / Graphics Plus.iso / general / modelers / geomview / source.lha / Geomview / src / lib / mg / gl / mggl.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-10-30  |  26.6 KB  |  1,024 lines

  1. /* Copyright (c) 1992 The Geometry Center; University of Minnesota
  2.    1300 South Second Street;  Minneapolis, MN  55454, USA;
  3.  
  4. This file is part of geomview/OOGL. geomview/OOGL is free software;
  5. you can redistribute it and/or modify it only under the terms given in
  6. the file COPYING, which you should have received along with this file.
  7. This and other related software may be obtained via anonymous ftp from
  8. geom.umn.edu; email: software@geom.umn.edu. */
  9.  
  10. /* Authors: Charlie Gunn, Stuart Levy, Tamara Munzner, Mark Phillips */
  11.  
  12. #include "mgP.h"
  13. #include "mgglP.h"
  14. #include "windowP.h"
  15. #include "mgglshade.h"
  16. #include <gl/gl.h>
  17. #include <stdio.h>
  18.  
  19. mgcontext * mggl_ctxcreate(int a1, ...);
  20. void        mggl_ctxset( int a1, ...  );
  21. int        mggl_feature( int feature );
  22. void        mggl_ctxdelete( mgcontext *ctx );
  23. int        mggl_ctxget( int attr, void* valueptr );
  24. int        mggl_ctxselect( mgcontext *ctx );
  25. void        mggl_sync( void );
  26. void        mggl_worldbegin( void );
  27. void        mggl_worldend( void );
  28. void        mggl_reshapeviewport( void );
  29. void        mggl_identity( void );
  30. void        mggl_transform( Transform T );
  31. int        mggl_pushtransform( void );
  32. int        mggl_poptransform( void );
  33. void        mggl_gettransform( Transform T );
  34. void        mggl_settransform( Transform T );
  35. int        mggl_pushappearance( void );
  36. int        mggl_popappearance( void );
  37. Appearance *mggl_setappearance( Appearance* app, int merge );
  38. Appearance *mggl_getappearance( void );
  39. int        mggl_setcamera( Camera* cam );
  40. int        mggl_setwindow( WnWindow *win, int final );
  41. mgglcontext *mggl_newcontext( mgglcontext *ctx );
  42.  
  43. extern void mggl_polygon();
  44. extern void mggl_mesh();
  45. extern void mggl_line();
  46. extern void mggl_polyline();
  47. extern void mggl_polylist();
  48. extern void mggl_quads();
  49.  
  50.  
  51.  
  52. void _mggl_ctxset(int a1, va_list *alist);
  53.  
  54. WnWindow *mgglwindow(WnWindow *win);
  55.  
  56. static unsigned long PackColorA(ColorA *c);
  57.  
  58. struct mgfuncs mgglfuncs = {
  59.   MGD_GL,
  60.   mgdevice_GL,
  61.   mggl_feature,
  62.   (mgcontext *(*)())mggl_ctxcreate,
  63.   mggl_ctxdelete,
  64.   (void (*)())mggl_ctxset,
  65.   mggl_ctxget,
  66.   mggl_ctxselect,
  67.   mggl_sync,
  68.   mggl_worldbegin,
  69.   mggl_worldend,
  70.   mggl_reshapeviewport,
  71.   mggl_settransform,
  72.   mggl_gettransform,
  73.   mggl_identity,
  74.   mggl_transform,
  75.   mggl_pushtransform,
  76.   mggl_poptransform,
  77.   mggl_pushappearance,
  78.   mggl_popappearance,
  79.   mggl_setappearance,
  80.   mggl_getappearance,
  81.   mggl_setcamera,
  82.   mggl_polygon,
  83.   mggl_polylist,
  84.   mggl_mesh,
  85.   mggl_line,
  86.   mggl_polyline,
  87.   mggl_quads,
  88.   mg_bezier
  89.   };
  90.  
  91. int
  92.   mgdevice_GL()
  93. {
  94.   _mgf = mgglfuncs;
  95.   if (_mgc != NULL && _mgc->devno != MGD_GL)
  96.     _mgc = NULL;
  97.   return(0);
  98. }
  99.  
  100. /*-----------------------------------------------------------------------
  101.  * Function:    mggl_ctxcreate
  102.  * Date:    Thu Jul 18 18:55:18 1991
  103.  * Author:    mbp
  104.  * Notes:    see mg.doc for rest of spec
  105.  */
  106. mgcontext *
  107. mggl_ctxcreate(int a1, ...)
  108. {
  109.   va_list alist;
  110.  
  111.  
  112.   _mgc =
  113.     (mgcontext*)mggl_newcontext( OOGLNewE(mgglcontext, "mggl_ctxcreate") );
  114.  
  115.   va_start(alist, a1);
  116.   _mggl_ctxset(a1, &alist);
  117.   va_end(alist);
  118.   return _mgc;
  119. }
  120.  
  121. /*-----------------------------------------------------------------------
  122.  * Function:    _mggl_ctxset
  123.  * Description:    internal ctxset routine
  124.  * Args:    a1: first attribute
  125.  *        *alist: rest of attribute-value list
  126.  * Returns:    nothing
  127.  * Author:    mbp
  128.  * Date:    Fri Sep 20 11:08:13 1991
  129.  * Notes:    mggl_ctxcreate() and mggl_ctxset() call this to actually
  130.  *        parse and interpret the attribute list.
  131.  */
  132. void
  133. _mggl_ctxset(int a1, va_list *alist)
  134. {
  135.   int attr;
  136.   WnWindow *owin;
  137.   char **ablock = NULL;
  138.  
  139. #define NEXT(type) OOGL_VA_ARG(type,alist,ablock)
  140.  
  141.   for (attr = a1; attr != MG_END; attr = NEXT(int)) {
  142.     switch (attr) {
  143.     case MG_ABLOCK:
  144.       ablock = NEXT(char**);
  145.       break;
  146.     case MG_ApSet:
  147.       {
  148.     Appearance *ap;
  149.  
  150.     if (ablock) {
  151.       ap = ApSet(NULL, AP_ABLOCK, ablock);
  152.     } else {
  153.       ap = _ApSet(NULL, va_arg(*alist, int), alist);
  154.     }
  155.  
  156.     mggl_setappearance(ap, MG_MERGE);
  157.     ApDelete(ap);
  158.       }
  159.       break;
  160.     case MG_WnSet:
  161.       if (ablock) {
  162.     WnSet( _mgc->win, WN_ABLOCK, ablock);
  163.       } else {
  164.     _WnSet( _mgc->win, va_arg(*alist, int), alist);
  165.       }
  166.       mggl_setwindow( _mgc->win, 0 );
  167.       break;
  168.     case MG_CamSet:
  169.       if (ablock) {
  170.     CamSet( _mgc->cam, CAM_ABLOCK, ablock);
  171.       } else {
  172.     _CamSet( _mgc->cam, va_arg(*alist, int), alist); break;
  173.       }
  174.     case MG_APPEAR: mgsetappearance(NEXT(Appearance *), MG_SET);
  175.       break;
  176.     case MG_WINDOW: mggl_setwindow( NEXT(WnWindow *), 0 ); break;
  177.     case MG_CAMERA: mggl_setcamera( NEXT(Camera*) ); break;
  178.     case MG_SETOPTIONS: _mgc->opts |= NEXT(int); break;
  179.     case MG_UNSETOPTIONS: _mgc->opts &= ~NEXT(int); break;
  180.     case MG_SHOW: _mgc->shown = NEXT(int); break;
  181.     case MG_PARENT: _mgc->parent = NEXT(mgcontext*); break;
  182.     case MG_BACKGROUND: _mgc->background = *NEXT(ColorA*); break;
  183.  
  184.     case MG_SHADER: mggl_setshader( NEXT(mgshadefunc) ); break;
  185.     case MG_SHADERDATA: _mgc->astk->shaderdata = NEXT(void*); break;
  186.  
  187.     case MG_SPACE:
  188.       {
  189.     int space = NEXT(int);
  190.     switch (TM_SPACE(space)) {
  191.     case TM_EUCLIDEAN:
  192.     case TM_SPHERICAL:
  193.       _mgc->space = space;
  194.       break;
  195.     case TM_HYPERBOLIC:
  196.       switch (TM_MODEL(space)) {
  197.       case TM_VIRTUAL:
  198.       case TM_PROJECTIVE:
  199.       case TM_CONFORMAL_BALL:
  200.         _mgc->space = space;
  201.         break;
  202.       default:
  203.         fprintf(stderr, "_mggl_ctxset: Illegal space value %1d\n", space);
  204.         break;
  205.       }
  206.       break;
  207.     default:
  208.       fprintf(stderr, "_mggl_ctxset: Illegal space value %1d\n", space);
  209.       break;
  210.     }
  211.       }
  212.       break;
  213.  
  214.     case MG_NDINFO: _mgc->NDinfo = NEXT(void *); break;
  215.     case MG_NDMAP:  _mgc->NDmap = NEXT(mgmapfunc); break;
  216.  
  217.     /* GL-specific */
  218.     case MG_ZNUDGE:
  219.     _mgc->zfnudge = NEXT(double);
  220.     if(_mgglc->born) mggl_init_zrange();
  221.     break;
  222.  
  223.     case MG_GLWINID:
  224.     _mgglc->win = NEXT(int);
  225.     break;
  226.  
  227.     case MG_GLXDISPLAY:
  228.     _mgglc->GLXdisplay = NEXT(void *);
  229.     break;
  230.  
  231.     default:
  232.       OOGLError (0, "_mggl_ctxset: undefined option: %d", attr);
  233.       return;
  234.     }
  235.   }
  236.  
  237.   if (_mgc->shown && !_mgglc->born) {
  238.  
  239.     /* open the window */
  240.     mgglwindow(_mgc->win);
  241.  
  242.     /* bring gl state into accordance with appearance state */
  243.     {
  244.       Appearance *ap = ApCopy( &(_mgc->astk->ap), NULL );
  245.       mggl_setappearance( ap, MG_SET );
  246.       ApDelete(ap);
  247.     }
  248.  
  249.   }
  250.  
  251. #undef NEXT
  252.  
  253. }
  254.  
  255.  
  256. /*-----------------------------------------------------------------------
  257.  * Function:    mggl_ctxget
  258.  * Description:    get a context attribute value
  259.  * Args:    attr: the attribute to get
  260.  *        value: place to write attr's value
  261.  * Returns:    1 for success; -1 if attr is invalid
  262.  * Author:    mbp
  263.  * Date:    Fri Sep 20 11:50:25 1991
  264.  * Notes:
  265.  */
  266. int
  267. mggl_ctxget(int attr, void* value)
  268. {
  269. #define VALUE(type) ((type*)value)
  270.  
  271.   switch (attr) {
  272.  
  273.   /* Attributes common to all MG contexts: */
  274.   case MG_APPEAR: *VALUE(Appearance*) = &(_mgc->astk->ap); break;
  275.   case MG_CAMERA: *VALUE(Camera*) = _mgc->cam; break;
  276.   case MG_WINDOW:
  277.     if(_mgglc->born) {
  278.         long x0, y0, xsize, ysize;
  279.         WnPosition wp;
  280.         getorigin(&x0, &y0);
  281.         getsize(&xsize, &ysize);
  282.         wp.xmin = x0; wp.xmax = x0+xsize-1;
  283.         wp.ymin = y0; wp.ymax = y0+ysize-1;
  284.         WnSet(_mgc->win, WN_CURPOS, &wp, WN_END);
  285.     }
  286.     *VALUE(WnWindow*) = _mgc->win;
  287.     break;
  288.   case MG_PARENT:    *VALUE(mgcontext*) = _mgc->parent; break;
  289.  
  290.   case MG_SETOPTIONS:
  291.   case MG_UNSETOPTIONS:    *VALUE(int) = _mgc->opts; break;
  292.  
  293.   case MG_BACKGROUND:    *VALUE(ColorA) = _mgc->background; break;
  294.  
  295.   case MG_SHADER:    *VALUE(mgshadefunc) = _mgc->astk->shader; break;
  296.   case MG_SHADERDATA:    *VALUE(void *) = _mgc->astk->shaderdata; break;
  297.   case MG_SPACE:    *VALUE(int) = _mgc->space; break;
  298.   case MG_NDINFO:    *VALUE(void *) = _mgc->NDinfo; break;
  299.   case MG_NDMAP:    *VALUE(mgmapfunc) = _mgc->NDmap; break;
  300.  
  301.   /* Attributes specific to GL contexts: */
  302.   case MG_GLWINID: *VALUE(int) = _mgglc->win; break;
  303.   case MG_GLBORN: *VALUE(int) = _mgglc->born; break;
  304.   case MG_GLZMAX: *VALUE(long) = _mgglc->zmax; break;
  305.   case MG_ZNUDGE: *VALUE(float) = _mgc->zfnudge; break;
  306.  
  307.   default:
  308.     OOGLError (0, "mggl_ctxget: undefined option: %d", attr);
  309.     return -1;
  310.  
  311.   }
  312.   return 1;
  313.  
  314. #undef VALUE
  315. }
  316.  
  317. /*-----------------------------------------------------------------------
  318.  * Function:    mgglwindow
  319.  * Description:    create a GL window
  320.  * Args:    *win: the WnWindow structure to realize
  321.  * Returns:    win if success, NULL if not
  322.  * Author:    mbp, slevy
  323.  * Date:    Fri Sep 20 11:56:31 1991
  324.  * Notes:    makes the GL calls necessary to create a GL window
  325.  *          corresponding to *win.  This involves the call to
  326.  *          winopen(), as well as various configuration things
  327.  *          like RGBmode(), zbuffer(), gconfig(), etc.
  328.  */
  329. WnWindow *
  330. mgglwindow(WnWindow *win)
  331. {
  332.   WnPosition pos;
  333.   int xsize, ysize, flag;
  334.   int zmin;
  335.   char *name;
  336.   char gver[80];
  337.  
  338.   mggl_setwindow(win, 1);
  339.  
  340.   RGBmode();
  341.   zbuffer(TRUE);
  342.   subpixel(TRUE);
  343.  
  344.   mmode(MPROJECTION);
  345.   loadmatrix( TM_IDENTITY );
  346.   mmode(MVIEWING);
  347.  
  348.   if(_mgglc->GLXdisplay == NULL) {
  349.       if(_mgc->opts & MGO_DOUBLEBUFFER)
  350.     doublebuffer();
  351.       gconfig();
  352.   }
  353.   _mgglc->oldopts = _mgc->opts;
  354.   _mgglc->born = 1;
  355.   _mgglc->zmax = getgdesc(GD_ZMAX);
  356.   _mgglc->zmin = getgdesc(GD_ZMIN);
  357.   mggl_init_zrange();
  358.  
  359.   _mgglc->cantwoside = getgdesc(GD_LIGHTING_TWOSIDE);
  360.  
  361.   gversion(gver);
  362.   _mgglc->is_PI = (strncmp(gver, "GL4DPI", 6) == 0);
  363.   _mgglc->turbo = (strncmp(gver, "GL4DPIT", 7) == 0);
  364.  
  365.   czclear(PackColorA(&(_mgc->background)), _mgglc->zmax);
  366.   if((_mgc->opts&MGO_DOUBLEBUFFER) && !(_mgc->opts&MGO_INHIBITSWAP) )
  367.     swapbuffers();
  368.  
  369.   return(win);
  370. }
  371.  
  372. /*-----------------------------------------------------------------------
  373.  * Function:    mggl_ctxset
  374.  * Description:    set some context attributes
  375.  * Args:    a1, ...: list of attribute-value pairs
  376.  * Returns:    nothing
  377.  * Author:    mbp
  378.  * Date:    Fri Sep 20 12:00:18 1991
  379.  */
  380. void mggl_ctxset( int a1, ...  )
  381. {
  382.   va_list alist;
  383.  
  384.   va_start( alist, a1 );
  385.   _mggl_ctxset(a1, &alist);
  386.   va_end(alist);
  387. }
  388.  
  389.  
  390. /*-----------------------------------------------------------------------
  391.  * Function:    mggl_feature
  392.  * Description:    report whether the GL device has a particular feature
  393.  * Args:    feature: the feature to report on
  394.  * Returns:    an int giving info about feature
  395.  * Author:    mbp
  396.  * Date:    Fri Sep 20 12:00:58 1991
  397.  * Notes:    -1 means the feature is not present.
  398.  *
  399.  *        NO OPTIONAL FEATURES SUPPORTED YET.  ALWAYS RETURNS -1.
  400.  */
  401. int mggl_feature( int feature )
  402. {
  403.   return(-1);
  404. }
  405.  
  406. /*-----------------------------------------------------------------------
  407.  * Function:    mggl_ctxdelete
  408.  * Description:    delete a GL context
  409.  * Args:    *ctx: context to delete
  410.  * Returns:    nothing
  411.  * Author:    slevy
  412.  * Date:    Tue Nov 12 10:29:04 CST 1991
  413.  * Notes:    Deleting the current context leaves the current-context
  414.  *        pointer set to NULL.
  415.  */
  416. void mggl_ctxdelete( mgcontext *ctx )
  417. {
  418.   if(ctx->devno != MGD_GL) {
  419.     mgcontext *was = _mgc;
  420.     mgctxselect(ctx);
  421.     mgctxdelete(ctx);
  422.     if(was != ctx)
  423.     mgctxselect(was);
  424.   } else {
  425.     if(((mgglcontext *)ctx)->born)
  426.     winclose(((mgglcontext *)ctx)->win);
  427.     mg_ctxdelete(ctx);
  428.     if(ctx == _mgc)
  429.     _mgc = NULL;
  430.   }
  431. }
  432.  
  433. /*-----------------------------------------------------------------------
  434.  * Function:    mggl_ctxselect
  435.  * Description:    select an MG context --- make it current
  436.  * Args:    *ctx: the context to become current
  437.  * Returns:    0 (why ???)
  438.  * Author:    mbp
  439.  * Date:    Fri Sep 20 12:04:41 1991
  440.  */
  441. int
  442. mggl_ctxselect( mgcontext *ctx )
  443. {
  444.   if(ctx == NULL || ctx->devno != MGD_GL) {
  445.     return mg_ctxselect(ctx);
  446.   }
  447.   /* Yes, it's a GL context.  Do something useful. */
  448.   _mgc = ctx;
  449.   if(_mgglc->win) {
  450.     if(_mgglc->GLXdisplay != NULL)
  451.       GLXwinset(_mgglc->GLXdisplay, _mgglc->win);
  452.     else
  453.       winset(_mgglc->win);
  454.   }
  455.   return(0);
  456. }
  457.  
  458. /*-----------------------------------------------------------------------
  459.  * Function:    mggl_sync
  460.  * Description:    flush buffered GL commands
  461.  * Returns:    nothing
  462.  * Author:    mbp
  463.  * Date:    Fri Sep 20 12:06:09 1991
  464.  * Notes:    Just flushes the GL buffer -- needed for remote displays.
  465.  */
  466. void
  467. mggl_sync( void )
  468. { gflush(); }
  469.  
  470. /*-----------------------------------------------------------------------
  471.  * Function:    mggl_worldbegin
  472.  * Description:    prepare to draw a frame
  473.  * Returns:    nothing
  474.  * Author:    mbp
  475.  * Date:    Fri Sep 20 12:06:58 1991
  476.  */
  477. void
  478. mggl_worldbegin( void )
  479. {
  480.   Transform V, S;
  481.  
  482.   if((_mgglc->oldopts ^ _mgc->opts) & MGO_DOUBLEBUFFER) {
  483.     if(_mgglc->GLXdisplay == NULL) {
  484.     if(_mgc->opts & MGO_DOUBLEBUFFER) doublebuffer();
  485.     else singlebuffer();
  486.     gconfig();
  487.     } else {
  488.     OOGLError(1, "Note: Can't change single/doublebuffer config of GLX window");
  489.     }
  490.     _mgglc->oldopts = _mgc->opts;
  491.   }
  492.  
  493.   RGBwritemask(_mgc->opts & MGO_NORED ? 0 : 255,
  494.         _mgc->opts & MGO_NOGREEN ? 0 : 255,
  495.         _mgc->opts & MGO_NOBLUE ? 0 : 255);
  496.  
  497.   /* Erase to background color & initialize z-buffer */
  498.   if(_mgc->opts & MGO_INHIBITCLEAR) zclear();
  499.   else czclear(PackColorA(&(_mgc->background)), _mgglc->zmax);
  500.  
  501.   mg_worldbegin();    /* Initialize W2C, C2W, W2S, S2W, etc. */
  502.  
  503.   _mgc->has = 0;
  504.  
  505.   /* Interpret the camera: load the proper matrices onto the GL matrix
  506.      stacks.  */
  507.   if(!(_mgc->opts & MGO_INHIBITCAM)) {
  508.       mmode(MPROJECTION);
  509.       CamViewProjection( _mgc->cam, V );
  510.       loadmatrix( V );
  511.       mmode(MVIEWING);
  512.       loadmatrix( _mgc->W2C );
  513.   }
  514.  
  515.   /* Bind the lights; do this here so we get lights in world coords. */
  516.   /* Only do this if we're supposed to do lighting */
  517.  
  518.   mg_globallights(_mgc->astk->lighting.lights, 1);
  519.  
  520.   if ( (_mgc->astk->lighting.lights != NULL) &&
  521.       (_mgc->astk->ap.shading != APF_CONSTANT))
  522.     mggl_lights(_mgc->astk->lighting.lights, _mgc->astk);
  523.  
  524.   /* Allow concave polygons.  This could be an Appearance attribute. */
  525.   concave(TRUE);
  526. }
  527.  
  528. /*-----------------------------------------------------------------------
  529.  * Function:    mggl_worldend
  530.  * Description:    finish drawing a frame
  531.  * Returns:    nothing
  532.  * Author:    mbp
  533.  * Date:    Fri Sep 20 12:08:02 1991
  534.  */
  535. void
  536. mggl_worldend( void )
  537. {
  538.   if((_mgc->opts&MGO_DOUBLEBUFFER) && !(_mgc->opts&MGO_INHIBITSWAP))
  539.     swapbuffers();
  540.   gflush();
  541. }
  542.  
  543. /*-----------------------------------------------------------------------
  544.  * Function:    mggl_reshapeviewport
  545.  * Description:    adjust to a new window size
  546.  * Returns:    nothing
  547.  * Author:    mbp
  548.  * Date:    Fri Sep 20 12:08:30 1991
  549.  * Notes:    adjusts both GL's internal viewport setting, as well as
  550.  *        MG context WnWindow's current position and camera's
  551.  *        aspect ratio.
  552.  */
  553. void
  554. mggl_reshapeviewport( void )
  555. {
  556.   long w, h;
  557.   float pixasp = 1;
  558.   WnPosition vp;
  559.  
  560.   WnGet(_mgc->win, WN_PIXELASPECT, &pixasp);
  561.   if(WnGet(_mgc->win, WN_VIEWPORT, &vp) <= 0) {
  562.     getsize(&w, &h);
  563.     reshapeviewport();
  564.   } else {
  565.     w = vp.xmax - vp.xmin + 1;
  566.     h = vp.ymax - vp.ymin + 1;
  567.     viewport(vp.xmin, vp.xmax, vp.ymin, vp.ymax);
  568.   }
  569.   CamSet(_mgc->cam, CAM_ASPECT, pixasp * (double)w/(double)h, CAM_END);
  570. }
  571.  
  572. /*-----------------------------------------------------------------------
  573.  * Function:    mggl_identity
  574.  * Description:    set the current object xform to identity
  575.  * Returns:    nothing
  576.  * Author:    mbp
  577.  * Date:    Fri Sep 20 12:23:48 1991
  578.  * Notes:    We use the GL ModelView matrix stack, not the mgcontext's
  579.  *        stack.
  580.  *
  581.  *        This assumes we're already in MVIEWING mode.
  582.  */
  583. void
  584. mggl_identity( void )
  585. {
  586.   /* [ obj xform ] = identity corresponds to having current W2C on
  587.      ModelView stack */
  588.   mggl_settransform( TM3_IDENTITY );
  589. }
  590.  
  591. /*-----------------------------------------------------------------------
  592.  * Function:    mggl_transform
  593.  * Description:    premultiply the object xform by T
  594.  * Args:    T
  595.  * Returns:    nothing
  596.  * Author:    mbp
  597.  * Date:    Fri Sep 20 12:24:57 1991
  598.  * Notes:    We use the GL ModelView matrix stack, not the mgcontext's
  599.  *        stack.
  600.  *
  601.  *        This assumes we're already in MVIEWING mode.
  602.  */
  603. void
  604. mggl_transform( Transform T )
  605. {
  606.   multmatrix(T);
  607.   TmConcat(T, _mgc->xstk->T, _mgc->xstk->T);
  608.   _mgc->has = _mgc->xstk->hasinv = 0;
  609. }
  610.  
  611. /*-----------------------------------------------------------------------
  612.  * Function:    mggl_pushtransform
  613.  * Description:    push the object xform stack
  614.  * Returns:    nothing (???)
  615.  * Author:    mbp
  616.  * Date:    Fri Sep 20 12:25:43 1991
  617.  * Notes:    We use the GL ModelView matrix stack, not the mgcontext's
  618.  *        stack.
  619.  *
  620.  *        This assumes we're already in MVIEWING mode.
  621.  */
  622. int
  623. mggl_pushtransform( void )
  624. {
  625.   pushmatrix();
  626.   mg_pushtransform();
  627. }
  628.  
  629. /*-----------------------------------------------------------------------
  630.  * Function:    mggl_popransform
  631.  * Description:    pop the object xform stack
  632.  * Returns:    nothing (???)
  633.  * Author:    mbp
  634.  * Date:    Fri Sep 20 12:25:43 1991
  635.  * Notes:    We use the GL ModelView matrix stack, not the mgcontext's
  636.  *        stack.
  637.  *
  638.  *        This assumes we're already in MVIEWING mode.
  639.  */
  640. mggl_poptransform( void )
  641. {
  642.   popmatrix();
  643.   mg_poptransform();
  644. }
  645.  
  646. /*-----------------------------------------------------------------------
  647.  * Function:    mggl_gettransform
  648.  * Description:    get the current object xform
  649.  * Args:    T: place to write the current object xform
  650.  * Returns:    nothing
  651.  * Author:    mbp
  652.  * Date:    Fri Sep 20 12:29:43 1991
  653.  * Notes:    We use the GL ModelView matrix stack, not the mgcontext's
  654.  *        stack.  This means we must multiply on the right by
  655.  *        the current C2W matrix after reading the GL ModelView
  656.  *        matrix.
  657.  *
  658.  *        This assumes we're already in MVIEWING mode.
  659.  */
  660. void
  661. mggl_gettransform( Transform T )
  662. {
  663.   TmCopy(_mgc->xstk->T, T);
  664. }
  665.  
  666. /*-----------------------------------------------------------------------
  667.  * Function:    mggl_settransform
  668.  * Description:    set the current object xform to T
  669.  * Args:    T
  670.  * Returns:    nothing
  671.  * Author:    mbp
  672.  * Date:    Fri Sep 20 12:29:43 1991
  673.  * Notes:    We use the GL ModelView matrix stack, not the mgcontext's
  674.  *        stack.  This means we must first load W2C onto the
  675.  *        modelview stact, then premult by T.
  676.  *
  677.  *        This assumes we're already in MVIEWING mode.
  678.  */
  679. void
  680. mggl_settransform( Transform T )
  681. {
  682.   loadmatrix( _mgc->W2C );
  683.   multmatrix( T );
  684.   TmCopy(T, _mgc->xstk->T);
  685.   _mgc->has = _mgc->xstk->hasinv = 0;
  686. }
  687.  
  688. /*-----------------------------------------------------------------------
  689.  * Function:    mggl_pushappearance
  690.  * Description:    push the MG context appearance stack
  691.  * Returns:    nothing
  692.  * Author:    mbp
  693.  * Date:    Fri Sep 20 12:54:19 1991
  694.  */
  695. int
  696. mggl_pushappearance( void )
  697. {
  698.   mg_pushappearance();
  699. }
  700.  
  701. /*-----------------------------------------------------------------------
  702.  * Function:    mggl_popappearance
  703.  * Description:    pop the MG context appearance stack
  704.  * Returns:    nothing
  705.  * Author:    mbp, munzner
  706.  * Date:    Fri Sep 20 12:54:19 1991
  707.  * Note:        We call mggl_lighting and mggl_material instead of
  708.  *              just doing lmbinds here because those procedures make the
  709.  *        proper existence checks and reset the GL drawing state.
  710.  */
  711. int
  712. mggl_popappearance( void )
  713. {
  714.   register struct mgastk *mastk = _mgc->astk;
  715.   register struct mgastk *mastk_next;
  716.  
  717.   if (! (mastk_next=mastk->next)) {
  718.     OOGLError(0, "mggl_popappearance: appearance stack has only 1 entry.");
  719.     return;
  720.   }
  721.  
  722.   if ((mastk->light_seq != mastk_next->light_seq) && /* changed */
  723.         IS_SHADED(mastk->next->ap.shading))    /* lighting on */
  724.       mggl_lighting(mastk_next, mastk_next->lighting.valid);
  725.   mggl_appearance(mastk_next, mastk_next->ap.valid);
  726.  
  727.   mg_popappearance();
  728. }
  729.  
  730. /*-----------------------------------------------------------------------
  731.  * Function:    mggl_setappearance
  732.  * Author:    munzner, mbp
  733.  * Date:    Wed Aug  7 01:08:07 1991
  734.  * Notes:    when app=NULL, mergeflag = MG_MERGE is assumed
  735.  *          (regardless of the actual value of mergeflag).
  736.  *          In this case, we make the GL calls to bring
  737.  *          the GL state into agreement with the current
  738.  *          appearance.
  739.  *
  740.  *        The above isn't true any more; update these comments
  741.  *        soon.  -- mbp Mon Sep 23 19:07:39 1991
  742.  *
  743.  *        things set here: material, lights, shading,
  744.  *          linewidth, transparency
  745.  *        things not set here: normals (drawing, scaling,
  746.  *          everting), drawing faces vs. edges
  747.  */
  748. Appearance *
  749. mggl_setappearance( Appearance* ap, int mergeflag )
  750. {
  751.   int changed, mat_changed, lng_changed;
  752.   struct mgastk *mastk = _mgc->astk;
  753.   Appearance *ma;
  754.   static float nullarray[] = { LMNULL };
  755.  
  756.   ma = &(mastk->ap);
  757.  
  758.   /* Decide what changes */
  759.   if (mergeflag == MG_MERGE) {
  760.     changed = ap->valid &~ (ma->override &~ ap->override);
  761.     mat_changed =
  762.       ap->mat ? ap->mat->valid &~ (ma->mat->override &~ ap->mat->override) : 0;
  763.     lng_changed =
  764.       ap->lighting ? ap->lighting->valid &~ 
  765.     (ma->lighting->override &~ ap->lighting->override) : 0;
  766.   }
  767.   else {
  768.     changed = ap->valid;
  769.     mat_changed = ap->mat ? ap->mat->valid : 0; 
  770.     lng_changed = ap->lighting ? ap->lighting->valid : 0; 
  771.   }
  772.  
  773.   /*
  774.    * Update current appearance; this needs to be done before making GL
  775.    * calls because it is conceivable that we might need to make a GL call
  776.    * corresponding to something in the current appearance for which the
  777.    * valid bit in *ap isn't set. (???)  By updating the current
  778.    * appearance before making GL calls, our GL calls can always take data
  779.    * from the current appearance, rather than worrying about whether to
  780.    * read *ap or the current appearance.
  781.    */
  782.   mg_setappearance( ap, mergeflag );
  783.  
  784.   /* Bring GL device into accord with new appearance */
  785.   if (_mgglc->born) {
  786.  
  787.     /*
  788.      * No bit in "changed" corresponds to {lighting,mat}.  We think of
  789.      * ap->{lighting,mat} as an extension to *ap which is interpreted to
  790.      * have all valid bits 0 if the {lighting,ap} pointer is NULL.  Note
  791.      * that this means there is no way for the parent to override the
  792.      * entire {lighting,mat} structure as a whole.  It can, however, set
  793.      * the individual override bits in the {lighting,mat} structure.
  794.      */
  795.     if ((ap->lighting) && (mastk->next)) {
  796.       if (mastk->light_seq == mastk->next->light_seq) {
  797.     mastk->light_seq++;
  798.     /*
  799.      * We need a new lighting model.
  800.      * To ensure we don't have any leftover garbage in GL's copy of this
  801.      * lighting model, we force GL to reset to defaults, then
  802.      * reinitialize everything.
  803.      */
  804.     lmdef(DEFLMODEL, mastk->light_seq, 0, nullarray);
  805.     lng_changed |= ma->lighting->valid;    /* "All fields changed" */
  806.       }
  807.     }
  808.     if (ma->shading != APF_CONSTANT && ap->lighting != NULL) {
  809.       mggl_lighting( mastk, lng_changed );
  810.     }
  811.  
  812.     /* Let mggl_material() decide if we need a new material */
  813.     if (ap->mat)
  814.       mggl_material( mastk, mat_changed );
  815.  
  816.     mggl_appearance( mastk, changed );
  817.  
  818.   }
  819.  
  820. }
  821.  
  822.  
  823. /*-----------------------------------------------------------------------
  824.  * Function:    mggl_getappearance
  825.  * Description:    return a ptr to current appearance
  826.  * Returns:    ptr to current appearance
  827.  * Author:    mbp
  828.  * Date:    Fri Sep 20 13:00:41 1991
  829.  * Notes:    Applications should not modify the returned appearance
  830.  *        in any way.
  831.  */
  832. Appearance *
  833. mggl_getappearance()
  834. {
  835.     return &(_mgc->astk->ap);
  836. }
  837.  
  838.  
  839. /*-----------------------------------------------------------------------
  840.  * Function:    mggl_setcamera
  841.  * Description:    set the context's camera (pointer)
  842.  * Args:    *cam: the camera to use
  843.  * Returns:    nothing
  844.  * Author:    mbp
  845.  * Date:    Fri Sep 20 13:07:31 1991
  846.  * Notes:    The context stores a pointer to the camera, not a copy
  847.  *        of it.
  848.  */
  849. int
  850. mggl_setcamera( Camera* cam )
  851. {
  852.   if (_mgc->cam) CamDelete(_mgc->cam);
  853.   _mgc->cam = cam;
  854.   RefIncr((Ref*) cam);
  855. }
  856.  
  857. /*
  858.  * Change current Window structure.
  859.  * If 'final' and otherwise appropriate, actually open the window.
  860.  * Apply relevant changes to window, if needed.
  861.  */
  862. int
  863. mggl_setwindow( WnWindow *win, int final )
  864. {
  865.   WnPosition pos, vp;
  866.   int xsize, ysize, flag, reconstrain;
  867.   int positioned = 0;
  868.   int zmin;
  869.   char *name, *oname;
  870.  
  871.   if(win == NULL)
  872.     return 0;
  873.  
  874.   reconstrain = 0;
  875.   if (WnGet(win, WN_PREFPOS, (void*)&pos) == 1 && (win->changed&WNF_HASPREF)) {
  876.     if(_mgglc->born) {
  877.     winposition(pos.xmin, pos.xmax, pos.ymin, pos.ymax);
  878.     win->changed &= ~(WNF_HASPREF|WNF_HASSIZE);
  879.     } else if(final) {
  880.     prefposition(pos.xmin, pos.xmax, pos.ymin, pos.ymax);
  881.     win->changed &= ~(WNF_HASPREF|WNF_HASSIZE);
  882.     reconstrain = positioned = 1;
  883.     }
  884.   } else if ((WnGet(win, WN_XSIZE, (void*)&xsize) == 1
  885.     && (WnGet(win, WN_YSIZE, (void*)&ysize) == 1
  886.     && (win->changed&WNF_HASSIZE))) ) {
  887.     prefsize(xsize, ysize);
  888.     reconstrain = 1;
  889.     win->changed &= ~WNF_HASSIZE;
  890.   }
  891.  
  892.  
  893.   if(reconstrain && _mgglc->born) {
  894.     WnGet(win, WN_NOBORDER, &flag);
  895.     if (flag) noborder();
  896.     winconstraints();
  897.     reconstrain = 0;
  898.   }
  899.  
  900.   if(_mgc->shown) {
  901.     WnGet(win, WN_NAME, &name);
  902.     if(_mgglc->born) {
  903.     if(name && (win->changed & WNF_HASNAME)) {
  904.         wintitle(name);
  905.         win->changed &= ~WNF_HASNAME;
  906.     }
  907.     if(WnGet(win, WN_VIEWPORT, &vp) > 0 && win->changed & WNF_HASVP) {
  908.         viewport(vp.xmin, vp.xmax, vp.ymin, vp.ymax);
  909.         win->changed &= ~WNF_HASVP;
  910.     }
  911.     } else if(final) {
  912.     foreground();
  913.     if(_mgglc->win <= 0)
  914.         _mgglc->win = winopen(name);
  915.     if(_mgglc->win == 0) {
  916.       OOGLError(0,"mgglwindow: bad return from winopen: %s",sperror());
  917.       return 0;
  918.     }
  919.     if(positioned)    /* 4.0 kludge: ensure the window is where we want it! */
  920.       winposition(pos.xmin, pos.xmax, pos.ymin, pos.ymax);
  921.     _mgglc->born = 1;
  922.     reconstrain = positioned;
  923.     }
  924.   }
  925.  
  926.   if((reconstrain && _mgglc->born)
  927.         || (win->changed & (WNF_NOBORDER|WNF_ENLARGE|WNF_SHRINK))) {
  928.     WnGet(win, WN_NOBORDER, &flag);
  929.     if (flag) noborder();
  930.  
  931.     WnGet(win, WN_ENLARGE, &flag);
  932.     if (flag) maxsize(getgdesc(GD_XPMAX), getgdesc(GD_YPMAX));
  933.  
  934.     WnGet(win, WN_SHRINK, &flag);
  935.     if (flag) minsize((long)40, (long)30);
  936.     reconstrain = 1;
  937.   }
  938.  
  939.   if (reconstrain && _mgglc->born) {
  940.     winconstraints();
  941.     win->changed &= ~(WNF_NOBORDER | WNF_ENLARGE | WNF_SHRINK);
  942.   }
  943.  
  944.   if(win != _mgc->win) {
  945.     RefIncr((Ref *)win);
  946.     WnDelete(_mgc->win);
  947.     _mgc->win = win;
  948.   }
  949.   return 1;
  950. }
  951.  
  952.  
  953.  
  954. /*-----------------------------------------------------------------------
  955.  * Function:    mggl_newcontext
  956.  * Description:    initialize a new mgglcontext structure
  957.  * Args:    *ctx: the struct to initialize
  958.  * Returns:    ctx
  959.  * Author:    mbp
  960.  * Date:    Fri Sep 20 13:11:03 1991
  961.  */
  962. mgglcontext *
  963. mggl_newcontext( mgglcontext *ctx )
  964. {
  965.   mg_newcontext(&(ctx->mgctx));
  966.   ctx->mgctx.devfuncs = &mgglfuncs;
  967.   ctx->mgctx.devno = MGD_GL;
  968.   ctx->mgctx.astk->ap_seq = 1;
  969.   ctx->mgctx.astk->mat_seq = 1;
  970.   ctx->mgctx.astk->light_seq = 1;
  971.   ctx->mgctx.zfnudge = 40.e-6;
  972.   ctx->born = 0;
  973.   ctx->win = 0;
  974.   ctx->d4f = c4f;
  975.   ctx->lmcolor = LMC_COLOR;
  976.   ctx->n3f = n3f;
  977.   VVINIT(ctx->room, char, 180);
  978.   ctx->GLXdisplay = NULL;
  979.   return ctx;
  980. }
  981.  
  982. /*-----------------------------------------------------------------------
  983.  * Function:    mggl_findctx
  984.  * Description: Given a GL window ID, returns the associated mg context.
  985.  * Returns:    mgcontext * for success, NULL if none exists.
  986.  * Author:    slevy
  987.  * Date:    Mon Nov 11 18:33:53 CST 1991
  988.  * Notes:    This is a public routine.
  989.  */
  990. mgcontext *
  991. mggl_findctx( int winid )
  992. {
  993.   register struct mgcontext *mgc;
  994.  
  995.   for(mgc = _mgclist; mgc != NULL; mgc = mgc->next) {
  996.     if(mgc->devno == MGD_GL && ((mgglcontext *)mgc)->win == winid)
  997.     return mgc;
  998.   }
  999.   return NULL;
  1000. }
  1001.  
  1002. /*-----------------------------------------------------------------------
  1003.  * Function:    PackColorA
  1004.  * Description:    Pack a ColorA struct into an unsigned long int for
  1005.  *          use by cpack() etc.
  1006.  * Args:    *c: the ColorA to pack
  1007.  * Returns:    the unsigned long corresponding to *c
  1008.  * Author:    mbp
  1009.  * Date:    Fri Sep 20 13:37:02 1991
  1010.  */
  1011. static unsigned long
  1012. PackColorA(ColorA *c)
  1013. {
  1014.   unsigned long val,r,g,b,a;
  1015.  
  1016.   r = c->r * 255;
  1017.   g = c->g * 255;
  1018.   b = c->b * 255;
  1019.   a = c->a * 255;
  1020.  
  1021.   val = (a << 24) | (b << 16) | (g << 8) | r;
  1022.   return(val);
  1023. }
  1024.